package com.game.common.cloud;

import com.game.common.model.ServerInfo;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * 网关业务服务管理
 */
@Service
public class BusinessServerService implements ApplicationListener<HeartbeatEvent> {
    private Logger logger = LoggerFactory.getLogger(BusinessServerService.class);
    private DiscoveryClient discoveryClient; // 服务发现客户端
    private KafkaTemplate<String, byte[]> kafkaTemplate; // kafka 客户端
    private Map<Integer, List<ServerInfo>> serverInfos; // serviceId 对应的服务器集合，一个服务可能部署到多台服务器上面，实现负载均衡
    @Autowired
    public BusinessServerService(DiscoveryClient discoveryClient, KafkaTemplate<String, byte[]> kafkaTemplate) {
        this.discoveryClient = discoveryClient;
        this.kafkaTemplate = kafkaTemplate;
    }

    @PostConstruct
    public void init() {
        this.refreshBusinessServerInfo();
    }

    public Set<Integer> getAllServiceId() {
        return this.serverInfos.keySet();
    }

    public KafkaTemplate<String, byte[]> getKafkaTemplate() {
        return this.kafkaTemplate;
    }
    @Override
    public void onApplicationEvent(HeartbeatEvent event) {
        this.refreshBusinessServerInfo();
    }

    @Override
    public boolean supportsAsyncExecution() {
        return ApplicationListener.super.supportsAsyncExecution();
    }

    /**
     * 根据playerId选择一个可用的服务器
     * @param serviceId
     * @param playerId
     * @return
     */
    public ServerInfo selectServerInfo(Integer serviceId, Long playerId) {
        Map<Integer, List<ServerInfo>> serverInfoMap = this.serverInfos;
        List<ServerInfo> serverList = serverInfoMap.get(serviceId);
        if (CollectionUtils.isEmpty(serverList)) {
            return null;
        }
        int hashCode = Math.abs(playerId.hashCode());
        int gatewayCount = serverList.size();
        int index = hashCode % gatewayCount;
        if (index >= gatewayCount) {
            index = gatewayCount - 1;
        }
        return serverList.get(index);
    }
    /**
     * 判断某个服务serverId是否可用
     * @param serviceId
     * @param serverId
     * @return
     */
    public boolean isEnableServer(Integer serviceId, Integer serverId) {
        Map<Integer, List<ServerInfo>> serverInfoMap = this.serverInfos;
        List<ServerInfo> serverInfos = serverInfoMap.get(serviceId);
        if (!CollectionUtils.isEmpty(serverInfos)) {
            return serverInfos.stream().anyMatch(serverInfo -> serverInfo.getServerId() == serverId);
        }
        return false;
    }

    /**
     *
     */
    private void refreshBusinessServerInfo() {
        Map<Integer, List<ServerInfo>> tempServerInfoMap = new HashMap<>();
        List<ServiceInstance> businessServiceInstances = discoveryClient.getInstances("game-logic"); // 获取所有game-logic服务实例
        logger.debug("抓取游戏服务配置成功，{}", businessServiceInstances);

        businessServiceInstances.forEach(instance -> {
            int weight = this.getServerInfoWeight(instance);
            for (int i = 0; i < weight; i++) {
                ServerInfo serverInfo = this.newServerInfo(instance);
                List<ServerInfo> serverList = tempServerInfoMap.get(serverInfo.getServiceId());
                if (CollectionUtils.isEmpty(serverList)) {
                    serverList = new ArrayList<>();
                    tempServerInfoMap.put(serverInfo.getServiceId(), serverList);
                }
                serverList.add(serverInfo);
            }
        });
        this.serverInfos = tempServerInfoMap;
    }
    private int getServerInfoWeight(ServiceInstance instance) {
        String value = instance.getMetadata().get("weight");
        if (value == null) {
            value = "1";
        }
        return Integer.parseInt(value);
    }

    private ServerInfo newServerInfo(ServiceInstance instance) {
        String serviceId = instance.getMetadata().get("serviceId");
        String serverId = instance.getMetadata().get("serverId");
        if(ObjectUtils.isEmpty(serviceId)) {
            throw new IllegalArgumentException(instance.getHost() + "的服务未配置serviceId");
        }
        if(ObjectUtils.isEmpty(serverId)) {
            throw new IllegalArgumentException(instance.getHost() + "的服务未配置serverId");
        }
        ServerInfo serverInfo = new ServerInfo();
        serverInfo.setServiceId(Integer.parseInt(serviceId));
        serverInfo.setServerId(Integer.parseInt(serverId));
        serverInfo.setHost(instance.getHost());
        serverInfo.setPort(instance.getPort());
        return serverInfo;
    }
}
